1. /* sdfexpds.cpp by K.Tsuru */
  2. // function ID 3313 DRADIX
  3. /**************************************************************************
  4. SDouble class
  5. It provides the exponential function exp(x).
  6. From the condition "exp(x) < DRADIX^DRADIX_EXP_MAX" the range of 'x' must be
  7. within
  8. |x| < DFIGURES*log(10)*DRADIX_EXP_MAX = 301759.17...
  9. [Algorithm of ExpDS()](divide and series method)
  10. step 1 :It divides 'x' into an integral part 'n' and a decimal one 'd'.
  11. x = n + d( n is integer and |d|<=0.5).
  12. step 2 :It reduces 'd' by taking M=2^m and f = d/M.
  13. step 3 :It evaluates y = e^f by the series.
  14. In this evaluation it divides 'f' such as
  15. f=S(short decimal)+L(long but very small decimal)
  16. and calculates y = (e^S)*(e^L).This processing uses the fact that
  17. the series(products) of short decimal can be rapidly evaluated.
  18. Using this it seems that step 2 is not necessary,but the calculation
  19. of e^S costs much time.
  20. ------------------------------------------------------------
  21. The method in which the reduction method is used only to e^S and calculates
  22. (e^(S/M))^M *(e^L) costs the same or more time.
  23. ------------------------------------------------------------
  24. step 4 :It restores the reduction by e^d=y^M.
  25. step 5 :It returns the value e^x = (e^n)*(e^d).
  26. ***************************************************************************/
  27. #ifndef SN_H
  28. #include "sn.h"
  29. #endif
  30. static const char* const func = "ExpDS";
  31. //It uses the series when the number of figures is less than this value.
  32. static const uint seriesFig = 15u;
  33. /*********************************************
  34. sub-function
  35. From 'dp' it determines 'rPow2' and 'upPrec'.
  36. **********************************************/
  37. static void GetReduceMethod(const SDouble& dp, int* rPow2, uint* upPrec){
  38. uint fig = dp.Last() - dp.First() +1u; //figure number of decimal part
  39. int k, exp = dp.NetRdxExp();
  40. //When even if 'fig' is small but the effective figures is large,it takes large 'k'.
  41. if(dp.MaxSize() >= 512u) k = 32;
  42. else if(fig < 128u) k = 8;
  43. else if(fig < 256u) k = 16;
  44. else k = 32;
  45. ulong f = (ulong)dp(dp.First()); // f<DRADIX<2^14 = 16384
  46. //Notice : ulong=32 bits, the value "f>>32" cannot be evaluated.
  47. if(!exp && (k < 32) && (f >> k) ){ //It makes the reduced value less than 1/DRADIX.
  48. //When k==8 only, it comes here because f/(2^16)=0.
  49. k *= 2;
  50. }
  51. //It gives the number of figures which temporally raising up precision.
  52. //That is the number of figures of 2^rPow2. The cancelation occures by this figures.
  53. *upPrec = uint( k*log10(2.0)/DFIGURES ) + 1u;
  54. *rPow2 = k;
  55. }
  56. /****************************
  57. sub-function
  58. It sets "result=exp(decPart)".
  59. *****************************/
  60. static void ExpLongDecPart(SDouble& decPart, SDouble& result){
  61. RealSize C;
  62. int j, rPow2;
  63. uint upPrec;
  64. GetReduceMethod(decPart, &rPow2, &upPrec);
  65. uint up = result.ProperUpPrec(upPrec);
  66. //It temporally raises up the precision if possible.
  67. if(up) C.SetEffFig(C.EffFigures() + up, C.TEMP_EXTEND);
  68. //step 2: It devides "decPart" by "2^rPow2".
  69. ulong dv;
  70. j = rPow2;
  71. if(j <= 16){
  72. dv = 1uL << j; // 2^16 = 65536 < SlOpMaxValue()
  73. decPart = DsDiv(decPart, dv);
  74. } else {
  75. dv = 1uL << 16; j /= 16;
  76. // 2^rPow2 = (2^16)^(rPow2/16) :It devides 'j' times by 2^16 .
  77. while(j > 0){ decPart = DsDiv(decPart, dv); j--; }
  78. }
  79. /*
  80. It uses the fact that the series of short decimal can be rapidly
  81. evaluated.
  82. e^d = e^s*e^(d-s) : 's' is a short decimal and |d-s|<<1.0.
  83. When "EffFigures()/4=500",it becomes about twice faster.
  84. */
  85. SDouble rr, sd, one(1.0);
  86. uint tk = seriesFig, df;
  87. df = decPart.Last() - decPart.First() +1u;
  88. //If the remaining figures is small it unifies.
  89. if(df/tk < 2u) tk = df;
  90. // step 3.1 :It takes out upper 'tk& figures and splits 'd' into 's' and 'd-s'.
  91. sd = decPart.TakeOutFigures(tk);
  92. decPart -= sd;
  93. // step 3.2:evaluation of exp(s)
  94. rr = ExpSeries(sd); // sd : short decimal
  95. #ifndef NDEBUG
  96. if(decPart.Sign()) assert(decPart.NetRdxExp() <= -(int)seriesFig);
  97. #endif
  98. // step 3.3 :evaluation of exp(d-s)
  99. if(decPart.Sign()){
  100. result = ExpSeries(decPart); // decPart :long but very small decimal fraction
  101. result *= rr;
  102. } else result = rr;
  103. // step 4 :It restores the reduction. result = result^p, p = 2^rPow2
  104. j = rPow2;
  105. while(j){ //If the value of 'rPow2' is taken too large it costs much time here.
  106. result *= result; j--; //(...(result^2)^2....^2)^2
  107. }
  108. if(up){
  109. C.SetEffFig(0); result.Reform(3301); //It shortens within the effective figures.
  110. }
  111. }
  112. /********************
  113. main body of ExpDS(x)
  114. *********************/
  115. static const double xMax = (double)DFIGURES*M_LN10*(double)DRADIX_EXP_MAX;
  116. // = 301759.17...
  117. SDouble ExpDS(const SDouble& x){
  118. SDouble one(1.0);
  119. if( x.IsMLT(one) ) return (one + x); // x = 0 or |x| << 1.0, x*x = 0;
  120. SDouble decPart, intPart;
  121. // step 1 :It splits into an integral part and decimal one.
  122. decPart = Modf(x, intPart);
  123. double iX = doubleD(intPart, 0), dX = doubleD(decPart, 0);
  124. // check the condition "exp(x) < DRADIX^DRADIX_EXP_MAX".
  125. #ifndef NDEBUG
  126. assert(xMax < (double)LONG_MAX);
  127. #endif
  128. if( fabs(iX) > xMax){ // exp(x) > D^(DRADIX_EXP_MAX)
  129. if(iX > 0.0) x.SetError(x.OVERFLOW_ERR, func, 3301);
  130. x.SetError(x.UNDERFLOW_ERR, func, -3301);
  131. return 0.0;
  132. }
  133. long ePow = iX; // iX < xMax < LONG_MAX
  134. //It reduces as |decPart| <= 0.5.
  135. // example : x = -1.8 --> intPart = -2, decPart = 0.2
  136. if(dX > 0.5){
  137. ePow++; decPart -= one;
  138. } else if(dX < -0.5){
  139. ePow--; decPart += one;
  140. }
  141. SDouble ePowInt;
  142. if(ePow) {
  143. ePowInt = Expower(ePow); //exp(ePow)
  144. if(decPart.Sign(3301) == 0) return ePowInt; // x is an integer.
  145. }
  146. //evaluation of exp(decPart)
  147. SDouble result;
  148. uint df = decPart.Last() - decPart.First() +1u;//number of figures of decimal part
  149. // seriesFig :If the number of figures is less than this value it uses the raw series.
  150. if( (df >= seriesFig) || (decPart.NetRdxExp() >= 0) ){ //long decimal
  151. ExpLongDecPart(decPart, result);
  152. } else {//If 'x' is short decimal and less than 1/DRADIX it is faster not to use the reduction.
  153. //It is better not to use the reduction method of x/(2^p) too.
  154. result = ExpSeries(decPart);
  155. }
  156. // step 5 :multply by exp(n)
  157. if(ePow) result *= ePowInt; // includes Reform()
  158. return result;
  159. }

sdfexpds.cpp : last modifiled at 2016/09/02 11:29:35(6,308 bytes)
created at 2017/10/07 10:22:50
The creation time of this html file is 2017/10/07 11:29:39 (Sat Oct 07 11:29:39 2017).